/*
 * AddressServiceImpl.java
 *
 * Created on 22. Juni 2009, 18:16
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package fhv.itb.mst2955.server;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import fhv.itb.mst2955.client.AddressService;
import fhv.itb.mst2955.client.model.AddressProxy;
import fhv.itb.mst2955.client.model.CountryProxy;
import fhv.itb.mst2955.server.persistence.Address;
import fhv.itb.mst2955.server.persistence.Country;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

/**
 *
 * @author Malcolm
 */
public class AddressServiceImpl extends RemoteServiceServlet implements
        AddressService {

    @PersistenceContext(unitName = "AddressBookNBPU")
    private EntityManager em;
    @Resource
    private UserTransaction utx;


    public Vector<AddressProxy> getAddresses() {
        Query q = em.createNamedQuery("Address.findAll");
        List<Address> addresses = q.getResultList();
        Vector<AddressProxy> ads = new Vector<AddressProxy>();

        for (Address a : addresses) {
            AddressProxy address = createAddressProxyFromAddress(a);
            ads.add(address);
        }

        return ads;
    }


    public Integer deleteAddress(int id) {
        try {
            utx.begin();
            em.joinTransaction();
            Address a = em.find(Address.class, id);
            if (a != null) {
                em.remove(a);
                utx.commit();
                return new Integer(1);
            }
        } catch (Exception ex) {
            Logger.getLogger(AddressServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
            try {
                utx.rollback();
            } catch (Exception ex1) {
                Logger.getLogger(AddressServiceImpl.class.getName()).log(Level.SEVERE, null, ex1);
            }
        }

        return new Integer(0);
    }


    public void putAddresses(Vector<AddressProxy> addresses) {

        try {
            utx.begin();
            em.joinTransaction();

            for (AddressProxy a : addresses) {
//                Query q = em.createNamedQuery("Address.findById").setParameter("id", a.getId());
//                Address sa = null;
                Address sa = em.find(Address.class, a.getId());

                try {
//                    sa = (Address) q.getSingleResult();
                    if (sa != null) {
                        if (a.getVersionNr() > sa.getVersionNr()) {
                            // overwrite server address with client address
                            sa = createAddressFromProxy(a);
                            em.merge(sa);
                        }
                    } else {
                        // insert client side address into server db
                        sa = createAddressFromProxy(a);
                        em.merge(sa);
                        em.persist(sa);
                    }
 
                } catch (NoResultException nre) {
                    // insert client side address into server db
                    sa = createAddressFromProxy(a);
                    em.merge(sa);
                    em.persist(sa);
                }
            }

            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (IllegalStateException ex1) {
                Logger.getLogger(AddressServiceImpl.class.getName()).log(Level.SEVERE, null, ex1);
            } catch (SecurityException ex1) {
                Logger.getLogger(AddressServiceImpl.class.getName()).log(Level.SEVERE, null, ex1);
            } catch (SystemException ex1) {
                Logger.getLogger(AddressServiceImpl.class.getName()).log(Level.SEVERE, null, ex1);
            }
            Logger.getLogger(AddressServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
        }

    }


    public void newAddress(AddressProxy address) {
        try {
            utx.begin();
            em.joinTransaction();
            Address a = createAddressFromProxy(address);
            em.merge(a);
            em.persist(a);
            utx.commit();
            System.out.println(new Date().getTime());
        } catch (Exception e) {
            try {
                utx.rollback();
            } catch (Exception ex) {
                Logger.getLogger(AddressServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }


    public Vector<CountryProxy> getCountries() {
        Query q = em.createNamedQuery("Country.findAll");
        List<Country> countries = q.getResultList();
        Vector<CountryProxy> cts = new Vector<CountryProxy>();

        for (Country c : countries) {
            CountryProxy country = createCountryProxyFromCountry(c);
            cts.add(country);
        }

        return cts;
    }


    // helpers
    /**
     * Creates a client-side AddressProxy from a server-side Address.
     *
     * @param a
     * The Address object to create a client-side AddressProxy from.
     *
     * @return
     * A client-side AddressProxy object.
     */
    public AddressProxy createAddressProxyFromAddress(Address a) {
        Query q = em.createNamedQuery("Country.findById");
        q.setParameter("id", a.getCountryID());
        Country c = (Country) q.getSingleResult();
        AddressProxy ap = new AddressProxy();
        ap.setId(a.getId());
        ap.setCity(a.getCity());
        ap.setStreet(a.getStreet());
        ap.setZip(a.getZip());
        ap.setCountryID(new Integer(a.getCountryID()));
        ap.setCountry(createCountryProxyFromCountry(c));
        ap.setVersionNr(a.getVersionNr());
        return ap;
    }


    /**
     * Creates a server-side Address from a client-side AddressProxy.
     *
     * @param ap
     * The AddressProxy object to create a server-side Address from.
     *
     * @return
     * A server-side Address object.
     */
    public static Address createAddressFromProxy(AddressProxy ap) {
        Address a = new Address();
        a.setId(ap.getId());
        a.setCountryID(ap.getCountryID());
        a.setCity(ap.getCity());
        a.setStreet(ap.getStreet());
        a.setZip(ap.getZip());
        a.setVersionNr(ap.getVersionNr());
        return a;
    }


    /**
     * Creates a client-side CountryProxy from a server-side Country.
     *
     * @param a
     * The Country object to create a client-side CountryProxy from.
     *
     * @return
     * A client-side CountryProxy object.
     */
    private CountryProxy createCountryProxyFromCountry(Country c) {
        CountryProxy cp = new CountryProxy();
        cp.setId(c.getId());
        cp.setName(c.getName());
        cp.setNickName(c.getNickName());
        return cp;
    }


//


    public void setUserTransaction(UserTransaction utx) {
        this.utx = utx;
    }


    public void setEntityManager(EntityManager em) {
        this.em = em;
    }



}
